package org.huzhp.gateway.filter.balance;

import com.netflix.loadbalancer.*;
import org.huzhp.gateway.filter.balance.rule.IpHashLoadBalancerRule;
import org.huzhp.gateway.filter.balance.rule.WeightLoadBalancerRule;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: java类作用描述
 * @Author: huzp
 * @CreateDate: 2020/4/16 15:07
 * @Version: 1.0
 */
public class GatewaySpringClientFactory  implements DisposableBean, ApplicationContextAware {

    private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap();

    public GatewaySpringClientFactory(){
    }

    public ILoadBalancer getLoadBalancer(String rule,String name) {
        ZoneAwareLoadBalancer zoneAwareLoadBalancer =  this.getInstance(name, ZoneAwareLoadBalancer.class);

        setRule(zoneAwareLoadBalancer,rule);

        return zoneAwareLoadBalancer;
    }

    private void setRule(ZoneAwareLoadBalancer zoneAwareLoadBalancer,String rule){
        if (zoneAwareLoadBalancer.getRule() instanceof RoundRobinRule){
            if (LbRule.IPHash.name().equalsIgnoreCase(rule)){
                zoneAwareLoadBalancer.setRule(new IpHashLoadBalancerRule());
            }else if (LbRule.Random.name().equalsIgnoreCase(rule)){
                zoneAwareLoadBalancer.setRule(new RandomRule());
            }else if (LbRule.Weight.name().equalsIgnoreCase(rule)){
                zoneAwareLoadBalancer.setRule(new WeightLoadBalancerRule());
            }else if(LbRule.ResponseTime.name().equalsIgnoreCase(rule)){
                zoneAwareLoadBalancer.setRule(new WeightedResponseTimeRule());
            }else if(LbRule.Zone.name().equalsIgnoreCase(rule)){
                zoneAwareLoadBalancer.setRule(new ZoneAvoidanceRule());
            }
        }
    }


    public <C> C getInstance(String name, Class<C> type) {
        AnnotationConfigApplicationContext context = this.getContext(name,type);
        return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0 ? context.getBean(type) : null;
    }

    protected AnnotationConfigApplicationContext getContext(String name, Class type) {
        if (!this.contexts.containsKey(name)) {
            synchronized(this.contexts) {
                if (!this.contexts.containsKey(name)) {
                    this.contexts.put(name, this.createContext(type));
                }
            }
        }

        return this.contexts.get(name);
    }

    protected AnnotationConfigApplicationContext createContext(Class type) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(type);
        context.refresh();
        return context;
    }

    @Override
    public void destroy() throws Exception {
        Collection<AnnotationConfigApplicationContext> values = this.contexts.values();
        Iterator var2 = values.iterator();

        while(var2.hasNext()) {
            AnnotationConfigApplicationContext context = (AnnotationConfigApplicationContext)var2.next();
            context.close();
        }

        this.contexts.clear();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    }
}
